use axum::{
    http::{header, HeaderValue, Method, StatusCode, Uri},
    response::{IntoResponse, Response},
    serve, Router,
};
use conn::online::{OnlineInfo, ONLINE_INFO};
use log::info;
use rust_embed::Embed;
use tokio::net::TcpListener;

use crate::{config, error::AppErr};

mod api;
mod conn;

pub async fn run() -> Result<(), AppErr> {
    info!("web server run:{}", config::WEB_ADDR);

    unsafe {
        ONLINE_INFO.init(OnlineInfo::new());
    }

    let ln = TcpListener::bind(config::WEB_ADDR).await?;
    let router = Router::new()
        .nest("/api", api::register())
        .fallback(on_static_handler);

    serve(ln, router).await?;

    Ok(())
}

#[derive(Embed)]
#[folder = "./like_web/dist"]
struct WebAssert;

async fn on_static_handler(method: Method, uri: Uri) -> Response {
    if method != Method::GET {
        return StatusCode::METHOD_NOT_ALLOWED.into_response();
    }

    let path = uri.path().trim_start_matches("/");
    let is_ext = path.contains('.');
    let path = if is_ext { path } else { "index.html" };

    if let Some(ef) = WebAssert::get(path) {
        let mut resp = ef.data.into_response();
        if let Ok(content_type) = HeaderValue::from_str(ef.metadata.mimetype()) {
            resp.headers_mut()
                .insert(header::CONTENT_TYPE, content_type);
        }
        resp
    } else {
        StatusCode::NOT_FOUND.into_response()
    }
}
